﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Storage;

class GameSession
{
    private static GameSession singleton;

    private int lastMap = 0;
    private int actualMap = 0;

    bool showDay = true;

    private Day actualDay, maxDay;

    public static int screenAdjustment = -54;

    private bool firstTime;

    private bool solved;

    private Vector2 startPosition;

    string music;

    private MapManager mapManager;

    public static bool ShowDay
    {
        get { return (singleton == null ? false : singleton.showDay); }
        set { singleton.showDay = value; }
    }

    public static Day ActualDay
    {
        get { return (singleton == null ? Day.NONE : singleton.actualDay); }
        set { singleton.actualDay = value; }
    }

    public static Player Player
    {
        get { return (singleton == null ? null : singleton.player); }
    }

    private DayManager dayManager;
    public static DayManager DayManager
    {
        get { return (singleton == null ? null : singleton.dayManager); }
    }

    private ScreenManager screenManager;
    public static ScreenManager ScreenManager
    {
        get { return (singleton == null ? null : singleton.screenManager); }
    }

    private GameplayScreen gameplayScreen;
    public static GameplayScreen GamePlayScreen
    {
        get { return (singleton == null ? null : singleton.gameplayScreen); }
    }

    public static bool IsActive
    {
        get { return singleton != null; }
    }

    Texture2D tiles, objects;
    public static Texture2D Tiles
    {
        get { return (singleton == null ? null : singleton.tiles); }
    }

    public static Texture2D Objects
    {
        get { return (singleton == null ? null : singleton.objects); }
    }

    private int tileSize, objectSize;
    public static int TileSize
    {
        get { return (singleton == null ? 0 : singleton.tileSize); }
    }

    public static int ObjectSize
    {
        get { return (singleton == null ? 0 : singleton.objectSize); }
    }

    public static ContentManager Content
    {
        get { return (singleton == null ? null : singleton.screenManager.Game.Content); }
    }

    private double silence = 0;

    private bool firsttime = true;

    private bool allDead;

    private bool reallyDead;

    private double time;

    private bool inTouch = false;

    private Player player;

    private List<Characters> charactersList;
    public static List<Characters> CharactersList
    {
        get { return (singleton == null ? null : singleton.charactersList); }
    }

    private static CharacterComparer charComparer;

    private string alert = @"Audio/Som de Alerta";
    private string door = @"Audio/door_1";
    private string chasing = @"Audio/Musica Perseguindo";

    public static void LoadContent(ContentManager content)
    {
        Globals.Font = content.Load<SpriteFont>("SpriteFont1");

        /*singleton.tiles = content.Load<Texture2D>(@"Textures/MapMock/tiles");
        singleton.tileSize = singleton.tiles.Width / 64;
        singleton.objects = content.Load<Texture2D>(@"Textures/MapMock/itens");
        singleton.objectSize = singleton.objects.Width / 64;*/
    }

    private GameSession(ScreenManager screenManager, GameplayScreen gameplayScreen)
    {
        // check the parameter
        if (screenManager == null)
        {
            throw new ArgumentNullException("screenManager");
        }
        if (gameplayScreen == null)
        {
            throw new ArgumentNullException("gameplayScreen");
        }

        // assign the parameter
        this.screenManager = screenManager;
        this.gameplayScreen = gameplayScreen;
        this.dayManager = new DayManager();

        // create the HUD interface

        music = @"Audio\Copy of Musica Menus";

        charComparer = new CharacterComparer();
    }

    public static void Update(GameTime gameTime)
    {
        // check the singleton
        if (singleton == null)
        {
            return;
        }

        foreach (Characters character in singleton.dayManager.npcList)
        {
            character.Update(gameTime);
        }
        singleton.player.Update(gameTime);
    }

    public static void Draw(GameTime gameTime)
    {
        //Sort Characters to Draw who is on top first.
        singleton.charactersList.Sort(charComparer);

        SpriteBatch spriteBatch = ScreenManager.SpriteBatch;

        spriteBatch.Begin();

        singleton.dayManager.Draw(gameTime, spriteBatch, (int)singleton.player.Position.X,
           (int)singleton.player.Position.Y);

        if (singleton.dayManager.actualDay != Day.ZERO && !Globals.CheckingMap)
            singleton.player.DrawHUD(gameTime, spriteBatch);

        spriteBatch.End();
    }

    public static void StartNewSession(ScreenManager screenManager, GameplayScreen gameplayScreen, string name, int charisma, int intelligence, int perception, Day day, Day maxDay)
    {

        Globals.IsPaused = false;

        if (screenManager == null)
        {
            throw new ArgumentNullException("screenManager");
        }
        if (gameplayScreen == null)
        {
            throw new ArgumentNullException("gameplayScreen");
        }

        // end any existing session
        EndSession();

        // create a new singleton
        if (singleton == null) singleton = new GameSession(screenManager, gameplayScreen);

        singleton.charactersList = new List<Characters>();

        singleton.actualDay = day;
        singleton.maxDay = maxDay;

        singleton.startPosition = new Vector2(200,430);

        singleton.firstTime = true;

        singleton.reallyDead = false;

        singleton.time = 0;

        //AudioManager.PlayMusic(singleton.music);

        AudioManager.ContinueMusic();
        Console.WriteLine("aki começa");

        singleton.charactersList.Add(singleton.player = new Player(Player.PlayerNumber.ONE, 5, 0, GetInicialPosition()));

        singleton.player.Name = name;
        singleton.player.Carisma = charisma;
        singleton.player.Inteligencia = intelligence;
        singleton.player.Percepcao = perception;

        singleton.dayManager.Load(singleton.actualDay);

        singleton.mapManager = singleton.dayManager.mapManager;

    }

    public static Vector2 GetInicialPosition()
    {
        switch (singleton.actualDay)
        {
            case Day.ZERO:
                return new Vector2(13 * 64, 2 * 64 + 30);
            case Day.ONE:
                return new Vector2(100, 630);
            case Day.TWO:
                if (Globals.CheckingMap)
                    return new Vector2(14 * 35, 14 * 26);
                return new Vector2( 1402, 3015);
            case Day.THREE:
                return new Vector2( 64 * 3, 64 * 5);
        }
        return Vector2.Zero;
    }

    public static void LoadDay(Day actualDay)
    {
        singleton.showDay = true; 
        singleton.actualDay = actualDay;
        if (actualDay > singleton.maxDay)
            singleton.maxDay = actualDay;

        singleton.player.Position = GetInicialPosition();
        singleton.dayManager.Load(singleton.actualDay);

        Globals.IsPaused = false;
    }

    public static void EndSession()
    {
        if (singleton != null)
        {
            GameplayScreen gameplayScreen = singleton.gameplayScreen;
            singleton.gameplayScreen = null;

            //AudioManager.StopMusic();

            Console.WriteLine("aki termina");

            singleton.charactersList.Clear();

            // clear the singleton
            singleton = null;

            if (gameplayScreen != null)
            {
                gameplayScreen.ExitScreen();
            }
        }
    }


    public static void LoadMap(int map)
    {
        singleton.dayManager.LoadMap(singleton.dayManager.actualDay, map);
    }

    public static bool CheckCollision(Rectangle position)
    {
        return singleton.dayManager.CheckCollision(position);
        //return singleton.mapManager.CheckCollision(position);
    }

    public static void ChangeMap(int map)
    {
        AudioManager.PlaySound(singleton.door);

        if (map == 1)
            singleton.player.Position = new Vector2((int)4.5 * 64, 2 * 64);
        if (map == 0)
            singleton.player.Position = new Vector2((int)4.5 * 64, (int)9 * 64);

        GameSession.LoadMap(map);
    }

    internal static void StartDialog()
    {
        singleton.screenManager.AddScreen(new DialogScreen());
    }

    public static void StartObject(Interaction interaction)
    {
        //singleton.screenManager.AddScreen(new ThoughtScreen(interaction.ThoughtList));


        if (interaction.Teleporte.Length > 0)
        {
            GameSession.LoadMap(interaction.Teleporte[0]);
            singleton.player.Position = new Vector2(interaction.Teleporte[1] * 64, interaction.Teleporte[2] * 64);
        }
        else
            singleton.screenManager.AddScreen(new ObjectInteractionScreen(interaction));
    }

    public static int GetInteractionCount()
    {
        int aux = singleton.player.Inteligencia / 2 + 1;

        if (aux < 1)
            aux = 1;

        return aux;
    }

    public static int GetCarisma()
    {
        return singleton.player.Carisma;
    }

    public static int GetPercepcao()
    {
        return singleton.player.Percepcao;
    }

    public static int GetInteligence()
    {
        return singleton.player.Inteligencia;
    }

    public static List<Condition> GetCondition()
    {
        //Console.WriteLine("numero: " + singleton.player.Condition.Count);
        return singleton.player.Condition;
    }


    public static void GiveCondition(List<Condition> give)
    {
        foreach(Condition condition in give)
        {
            if (condition.ToRemove)
                singleton.player.RemoveCondition(condition);
            else
            if (!GameSession.CheckCondition(condition, true))
                singleton.player.ReceiveCondition(condition);
        }
    
    }

    public static bool CheckCondition(Condition condition, bool give)
    {
        bool returnValue = false;

        if (condition == null)
            returnValue = true;

        if (condition.Kind == ConditionKind.ATRIBUTE)
        {
            if (condition.Atributo == Atributo.CARISMA)
            {
                if (GameSession.GetCarisma() >= condition.Quantidade)
                    returnValue = true;
            }
            if (condition.Atributo == Atributo.INTELIGENCIA)
            {
                if (GameSession.GetInteligence() >= condition.Quantidade)
                    returnValue = true;
            }
            if (condition.Atributo == Atributo.PERCEPCAO)
            {
                if (GameSession.GetPercepcao() >= condition.Quantidade)
                    returnValue = true;
            }
        }

        if (condition.Kind == ConditionKind.ITEM && !give)
        foreach (Item item in singleton.player.ItemList)
        {
            if (item.Name.Equals(condition.ID) && item.Quantidade >= condition.Quantidade )
                returnValue = true;
        }
        
        if(condition.Kind == ConditionKind.LICENSE)
        foreach(Condition cond in singleton.player.Condition)
        {
            if (cond.ID.Equals(condition.ID))
                returnValue = true;
        }

        if (condition.IsTrue)
            return returnValue;
        else
            return !returnValue;
    }

    public static Dictionary<int, Dialog> GetDialog(Day day, int p)
    {
        return singleton.dayManager.npcList[p].Dialogos;
    }

    internal static NPC GetNPC(Day day, int p)
    {
        return singleton.dayManager.npcList[p];
    }

    internal static Rectangle GetBounds()
    {
        return singleton.player.BoundingRectangle;
    }

    internal static string GetPosition()
    {
        return " " + singleton.player.Position.X + " " + singleton.player.Position.Y; 
    }

    internal static void StartDialog(NPC nextfrom)
    {
        singleton.screenManager.AddScreen(new DialogScreen(nextfrom));
    }

    internal static bool CheckAllConditions(List<Condition> list)
     {
        foreach(Condition condition in list)
        {
            if (!GameSession.CheckCondition(condition, false))
            {
                return false;
            }
        }

        return true;
    }

    internal static void DayCompleted()
    {
        if ((int)singleton.actualDay + 1 > (int)singleton.maxDay)
            singleton.maxDay = (Day)singleton.actualDay + 1;

        SavedGameManager save = new SavedGameManager();
        save.SaveGame(singleton.player, singleton.maxDay);

        Globals.IsPaused = true;

        ScreenManager.AddScreen(new DaySelectionScreen(singleton.maxDay, singleton.player.Name,
            singleton.player.Carisma, singleton.player.Inteligencia, singleton.player.Percepcao));
    }

    internal static string GetObjetives()
    {
        switch (singleton.actualDay)
        {
            case Day.ONE:
                return "Assinar o contrato.";
            case Day.TWO:
                return "Achar caneta funcionando.";
        }
        return "DIA SEM OBJETIVO";
    }

    internal static void ReturnDaySelectionScreen()
    {
        Globals.IsPaused = true;

        ScreenManager.AddScreen(new DaySelectionScreen(singleton.maxDay, singleton.player.Name,
            singleton.player.Carisma, singleton.player.Inteligencia, singleton.player.Percepcao));
    }
}